package profileService

import (
	"context"
	"go.mongodb.org/mongo-driver/mongo"
	"go.uber.org/zap"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	blobpb "serve/blob/api/gen/v1"
	rentalpb "serve/rental/api/gen/v1"
	"serve/rental/profile/client/orc"
	"serve/rental/profile/dao"
	"serve/shared/antu/auth"
	"serve/shared/id"
	"time"
)

type Service struct {
	Mongo             *dao.Mongo
	Logger            *zap.Logger
	BlobClient        blobpb.BlobServiceClient
	PhotoGetExpire    time.Duration
	PhotoUploadExpire time.Duration
	OCrManager        OCrManager
}

type OCrManager interface {
	DriverLicenseOcr(ctx context.Context, url string) (*orc.DriverLicense, error) // 驾驶证识别
}

func (s *Service) GetProfile(ctx context.Context, req *rentalpb.GetProfileRequest) (*rentalpb.Profile, error) {
	aid, err := auth.AccountIDFromContext(ctx)
	if err != nil {
		return nil, status.Errorf(codes.Unauthenticated, "获取身份信息失败")
	}

	pr, err := s.Mongo.GetProfile(ctx, aid)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return &rentalpb.Profile{}, nil
		}
		s.Logger.Info("cannot get GetProfile ", zap.Error(err))
		return nil, status.Errorf(codes.Internal, "")
	}

	if pr.Profile == nil {
		return &rentalpb.Profile{}, nil
	}
	return pr.Profile, nil
}

func (s *Service) SubmitProfile(ctx context.Context, in *rentalpb.Identity) (*rentalpb.Profile, error) {
	aid, err := auth.AccountIDFromContext(ctx)
	if err != nil {
		return nil, status.Errorf(codes.Unauthenticated, "获取身份信息失败")
	}
	//profile, err := s.Mongo.GetProfile(ctx, aid)

	p := &rentalpb.Profile{
		Identity:        in,
		Identity_Status: rentalpb.Identity_Status_PENDING,
	}

	err = s.Mongo.UpdateProfile(ctx, aid, rentalpb.Identity_Status_PENDING, p)
	if err != nil {
		s.Logger.Error("cannot update Profile", zap.Error(err))
		return nil, status.Errorf(codes.Internal, "")
	}

	go func() {
		time.Sleep(3 * time.Second)
		err := s.Mongo.UpdateProfile(context.Background(), aid, rentalpb.Identity_Status_PENDING, &rentalpb.Profile{
			Identity:        in,
			Identity_Status: rentalpb.Identity_Status_VERIFIED,
		})

		if err != nil {
			s.Logger.Error("自动更新审核状态失败", zap.Error(err))
		}
	}()
	return p, nil
}

func (s *Service) ClearProfile(ctx context.Context, in *rentalpb.ClearProfileRequest) (*rentalpb.Profile, error) {
	aid, err := auth.AccountIDFromContext(ctx)
	if err != nil {
		return nil, status.Errorf(codes.Unauthenticated, "获取身份信息失败")
	}

	p := &rentalpb.Profile{}

	err = s.Mongo.DeleteProfile(ctx, aid)
	if err != nil {
		s.Logger.Error("cannot update Profile", zap.Error(err))
		return nil, status.Errorf(codes.Internal, "")
	}
	return p, nil
}

//GetProfilePhoto 获取图片
func (s *Service) GetProfilePhoto(ctx context.Context, req *rentalpb.GetProfilePhotoRequest) (*rentalpb.GetProfilePhotoResponse, error) {

	aid, err := auth.AccountIDFromContext(ctx)
	if err != nil {
		return nil, status.Errorf(codes.Unauthenticated, "获取身份信息失败")
	}

	pr, err := s.Mongo.GetProfile(ctx, aid)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return nil, status.Error(codes.NotFound, "")
		}
		s.Logger.Info("cannot get GetProfilePhoto ", zap.Error(err))
		return nil, status.Errorf(codes.Internal, "")
	}

	if pr.PhotoBlobID == "" {
		return nil, status.Error(codes.NotFound, "")
	}

	url, err := s.BlobClient.GetBlobURL(ctx, &blobpb.GetBlobURLRequest{
		Id:                  pr.PhotoBlobID,
		UploadUrlTimeoutSec: int32(s.PhotoGetExpire.Seconds()),
	})
	if err != nil {
		s.Logger.Error("cannot get blob", zap.Error(err))
		return nil, status.Error(codes.Internal, "")
	}
	return &rentalpb.GetProfilePhotoResponse{Url: url.Url}, nil
}

func (s *Service) CreateProfilePhoto(ctx context.Context, req *rentalpb.CreateProfilePhotoRequest) (*rentalpb.CreateProfilePhotoResponse, error) {
	aid, err := auth.AccountIDFromContext(ctx)
	if err != nil {
		return nil, status.Errorf(codes.Unauthenticated, "获取身份信息失败")
	}

	blob, err := s.BlobClient.CreateBlob(ctx, &blobpb.CreateBlobRequest{
		AccountId:           aid.String(),
		UploadUrlTimeoutSec: int32(s.PhotoUploadExpire.Seconds()),
	})

	if err != nil {
		s.Logger.Error("cannot Create blob", zap.Error(err))
		return nil, status.Error(codes.Internal, "")
	}

	err = s.Mongo.UpdateProfilePhoto(ctx, aid, id.BlobID(blob.Id))
	if err != nil {
		s.Logger.Error("cannot UpdateProfilePhoto", zap.Error(err))
		return nil, status.Error(codes.Aborted, "")
	}

	return &rentalpb.CreateProfilePhotoResponse{
		UploadUrl: blob.UploadUrl,
	}, nil
}

//CompleteProfilePhoto 行驶证识别
func (s *Service) CompleteProfilePhoto(ctx context.Context, req *rentalpb.CompleteProfilePhotoRequest) (*rentalpb.Identity, error) {
	aid, err := auth.AccountIDFromContext(ctx)
	if err != nil {
		return nil, status.Errorf(codes.Unauthenticated, "获取身份信息失败")
	}
	pr, err := s.Mongo.GetProfile(ctx, aid)
	if err != nil {
		if err == mongo.ErrNoDocuments {
			return nil, status.Error(codes.NotFound, "")
		}
		s.Logger.Info("cannot get GetProfilePhoto ", zap.Error(err))
		return nil, status.Errorf(codes.Internal, "")
	}

	if pr.PhotoBlobID == "" {
		return nil, status.Error(codes.NotFound, "")
	}

	Url, err := s.BlobClient.GetBlobURL(ctx, &blobpb.GetBlobURLRequest{
		Id:                  pr.PhotoBlobID,
		UploadUrlTimeoutSec: int32(s.PhotoGetExpire.Seconds()),
	})
	if err != nil {
		s.Logger.Info("cannot get GetBlob ", zap.Error(err))
		return nil, status.Errorf(codes.Aborted, "")
	}

	// 行驶证识别
	content, err := s.OCrManager.DriverLicenseOcr(ctx, Url.Url)
	if err != nil {
		s.Logger.Error("ocr err", zap.Error(err))
		return &rentalpb.Identity{}, nil
	}

	return &rentalpb.Identity{
		LicNumber:       content.LicenseNumber,
		Name:            content.Name,
		Gender:          transformationSex(content.Sex),
		BirthDateMillis: content.BirthDate * 1000,
	}, nil
}

func (s *Service) ClearProfilePhoto(ctx context.Context, request *rentalpb.ClearProfilePhotoPhotoRequest) (*rentalpb.ClearProfilePhotoPhotoResponse, error) {
	aid, err := auth.AccountIDFromContext(ctx)
	if err != nil {
		return nil, status.Errorf(codes.Unauthenticated, "获取身份信息失败")
	}

	err = s.Mongo.UpdateProfilePhoto(ctx, aid, "")
	if err != nil {
		return nil, status.Errorf(codes.Internal, "")
	}
	return &rentalpb.ClearProfilePhotoPhotoResponse{}, nil
}

func transformationSex(sex string) rentalpb.Gender {
	if sex == "男" {
		return rentalpb.Gender_MALE
	}
	if sex == "女" {
		return rentalpb.Gender_FEMALE
	}
	return rentalpb.Gender_G_NOT_SPECIFIED
}
